/**
 * @fileoverview Class creator
 */

/**
 * @const Class handling properties and methods
 */
Dx.Class = {};


Dx.assign(Dx.Class,

   /** @lends Dx.Class */ ({

      declaring: false,

      processing: false,

      baseClassName: 'Object',

   /**
    * class names index by path
    */
      paths: {},

      pathNames: [],

      namespaces: {},

   /**
    * classes not yet declared
    */
      declareList: [],

      definitionprocessorsOrder: [],

      definitionprocessors: {},

      preprocessorsOrder: [],

      preprocessors: {},

      processorsOrder: [],

      processors: {},

      postprocessorsOrder: [],

      postprocessors: {},

      temporaryCallbacks: {},

   /**
    * Applies class property to Dx based class
    * @private
    */
      _callback_createClassProperty: function(name, value, properties) {

         if (properties.hasOwnProperty(name)) {

            if (name == 'constructor') {

               name = '_construct';

            }

            if (Dx.isFunction(value)) {

               if (name in this) {

                  value.$parent = this[name];

               }

            }

            /** @this {Object} */
            this[name] = value;

         }

      },

   /**
    * Applies Dx properties to non-Dx class
    * @private
    */
      _callback_createNonDxClassProperty: function(name, value, properties) {

         if (name != 'constructor' || name != '_construct') {

            this[name] = value;

         }

      },

   /**
    * Fix non-Dx Class properties by inheriting properties from Dx Base Class
    * @private
    */
      _fixNonDxClass: function(Prototype, SuperPrototype) {

         var D = Dx;

         D.each(

            D.Base.prototype,

            this._callback_createNonDxClassProperty,

            Prototype

         );

         Prototype._construct = SuperPrototype.constructor;

      },

   /**
    * assign non-processor property to an object to be used to create
    *    class property
    * @private
    */
      _callback_assignNonProcessorProperty: function(name, value, properties) {

         if (name.charAt(0) != '@') {

            this[name] = value;

         }

      },

   /**
    * Parses path and calls the callback if a name in path is found delimited
    *    by "."
    * @private
    * @param {String} path the path to parse (e.g. "Namespace.MyClass")
    * @param {Function} callback the function callback when
    *    a name in path is found. arguments of the callback should include
    *    the following arguments: name, callbackObject
    *    "returnValue" propety assigned to callbackObject will be returned in
    *    the main function.
    *    returning Boolean false in the callback will stop the parsing of path
    * @param {*=} scope Scope of the callback function.
    * @return {*}
    */
      _parsePath: function(path, callback, scope) {

         var anchor = 0;

         var callbackObject = {

               from: anchor,

               to: anchor,

               ended: false,

               returnValue: void(0)

            };

         for (var ended, word, end = 0, c = -1, l = path.length; l--;) {

            ended = !l;

            if (path.charAt(++c) == '.' || ended) {

               if (anchor != c) {

                  end = ended ? c + 1 : c;

                  callbackObject.from = anchor;

                  callbackObject.to = end;

                  callbackObject.ended = ended;

                  word = path.substring(anchor, end);

                  if (callback.call(scope, word, callbackObject) === false) {

                     break;

                  }

               }

               anchor = ++c;

            }

         }

         var returnValue = callbackObject.returnValue;

         Dx.clearObject(callbackObject);

         return returnValue;

      },

   /**
    * callback of _parsePath() that sets obj.returnValue with the
    *    found object from the given path. Else it is set to undefined
    *    and return false if not to stop the parser.
    * @protected
    * @this starting object to traverse for concurrent property path.
    *    defaults to "D.GLOBAL"
    * @param {String} name name token of the parsed path
    * @param {Object} obj parse object,
    *    only "returnValue" property is meaningful for this method
    * @return {Boolean|*} false to stop the parser, or any value to proceed
    */
      _callback_getObjectFromNamespace_parsePath: function(name, obj) {

         var D = Dx;
         
         var current = obj.returnValue || this;

         var found = (D.isObject(current, false) || D.isFunction(current)) &&

            name in current;
            
         

         obj.returnValue = found ? current[name] : void(0);

         return found;

      },

   /**
    * callback of _parsePath() that sets obj.returnValue with the
    *    found object from the given path. Else it creates
    *    a new Object to fill-in the path to populate the namespace objects.
    * @protected
    * @param {String} name name token of the parsed path
    * @param {Object} obj parse object,
    *    only "returnValue" property is meaningful for this method
    * @return {Boolean|*} false to stop the parser, or any value to proceed
    */
      _callback_namespace_parsePath: function(name, obj) {

         var D = Dx;

         var currentName = (obj.currentNs || 'GLOBAL');

         var current = obj.returnValue || D.GLOBAL;

         var found = name in current && current[name];

         if (!D.isObject(found, false) && !D.isFunction(found)) {

            found = current[name] = {};

         }

         obj.currentNs = currentName + '.' + name;

         obj.returnValue = found;

      },

   /**
    * callback of _parsePath() that sets obj.returnValue with the
    *    declared namespace object from the given path. It will cascade-create
    *    namespace objects until it has covered all path
    * @protected
    * @param {String} name name token of the parsed path
    * @param {Object} obj parse object,
    *    only "returnValue" property is meaningful for this method
    * @return {Boolean|*} false to stop the parser, or any value to proceed
    */
      _callback_namespace_declarePath: function(name, obj) {

         var nsName = obj.currentNsName || '';

         var nsObj = this.createNsDeclareObject(nsName);

         var nsInstance = obj.returnValue || Dx.GLOBAL;

         nsObj.ns = nsName;

         nsObj.name = obj.name;

         // update ns Symbol Table copy
         this._callback_namespace_parsePath(name, obj);

         // link
         var childIndexes = nsObj.children;

         var childNames = nsObj.childNames;

         var indexNotFound = !childIndexes.hasOwnProperty(name);

         if (!childIndexes.hasOwnProperty(name)) {

            childNames[childNames.length] = name;

            childIndexes[name] = true;

         }

         // update ns name
         obj.currentNsName = nsName ? (nsName + '.' + name) : name;

         // finalize returnValue
         if (obj.ended) {

            obj.returnValue = [nsObj, name, nsInstance];

         }

      },

   /**
    * callback of _parsePath() that sets obj.returnValue with the
    *    namespace and name parts of the path.
    * @protected
    * @param {String} name name token of the parsed path
    * @param {Object} obj parse object,
    *    only "returnValue" property is meaningful for this method
    * @return {Boolean|*} false to stop the parser, or any value to proceed
    */
      _callback_createPathObject: function(name, obj) {

         var o = obj.returnValue;

         var start = !o;

         if (start) {

            obj.returnValue = o = {

               fullName: '',

               ns: '',

               name: ''

            };

         }

         if (obj.ended) {

            o.name = name;

            o.fullName = o.ns ?

               o.ns + '.' + name :

                  name;

         } else if (start) {

            o.ns = name;

         } else {

            o.ns += '.' + name;

         }

      },

   /**
    * process the Declaration Object with the given processor prefix.
    *    e.g.:
    *       to preprocess the object use prefix "pre"
    *       to postprocess the object use prefix "post"
    *
    * @private
    * @param {String} prefix the processor prefix to use
    * @param {Object} declareObject the declaration object to be processed.
    */
      _processDeclaration: function(prefix, declareObject, applyCallbacks) {

         // disable declare() when processing
         var oldProcessFlag = this.processing;

         this.processing = true;

         var processorName = (prefix || '') + 'processors';

         var processors = processorName in this && this[processorName];

         if (processors) {

            var order = this[processorName + 'Order'];

            var definition = declareObject.definition;

            var properties = declareObject.properties;

            var processName, propertyName, processValue;

            for (var c = -1, l = order.length; l--;) {

               propertyName = order[++c];

               processName = '@' + propertyName;

               processValue = definition.hasOwnProperty(processName) ?

                  definition[processName] : void(0);

               if (processors[propertyName].call(

                     this,

                     processValue,

                     declareObject

                  ) === true) {

                  properties[processName] = processValue;

               }

            }

            // apply callbacks
            if (applyCallbacks !== false) {

               this.callCallbacks(

                  declareObject.path,

                  prefix || 'process',

                  declareObject

               );

            }

         }

         this.processing = oldProcessFlag;

      },

   /**
    * callback if Class declaration object is ready to be declared
    * @protected
    * @param {Object} declareObject the declaration object to be used for
    *    declaring class
    */
      onDeclare: function(declareObject) {

         // process
         this._processDeclaration('pre', declareObject);

         // process
         this._processDeclaration('', declareObject);

         // postprocess
         this._processDeclaration('post', declareObject);

         declareObject.declared = true;

         this.callCallbacks(

            declareObject.path,

            'declared',

            declareObject.path,

            declareObject.instance,

            declareObject.Class

         );

      },

   /**
    * callback if instance discovered is to be declared
    * @protected
    * @param {Object} pathObject path object consisting of namespace and path
    *    info parsed from a given JSON path.
    * @param {Object} discoveredObject the instance to be used for the
    *    declaration object
    */
      onDiscover: function(pathObject, discoveredObject) {

         var path = pathObject.ns + '.' + pathObject.name;

         var declareObject = this.createDeclareObject(path);

         this.registerDeclaration(declareObject);

         // no more processing. just callbacks
         declareObject.instance = discoveredObject;

         declareObject.declared = true;

         var isSingleton = !Dx.isFunction(discoveredObject);

         declareObject.isSingleton = isSingleton;

         if (isSingleton) {

            declareObject.Class = discoveredObject.constructor.prototype;

         } else {

            declareObject.Class = discoveredObject.prototype;

         }

         // apply callbacks
         this.callCallbacks(

            declareObject.path,

            'declared',

            declareObject.path,

            declareObject.instance,

            declareObject.Class

         );

      },

   /**
    * checks if class path "name" can be declared and all requirements needed
    *    for a class to declare are met.
    * @param {String} name the class path (e.g. "Dx.MyClass")
    * @return {Boolean} true if it can declare or false.
    */
      canDeclare: function(name) {

         var o = this.getDeclaration(name);

         if (!!o && !o.declared) {

            // check required class declaration
            var requires = o.requires;

            for (var l = requires.length; l--;) {

               if (this.isDeclared(requires[l])) {

                  requires.splice(l, 1);

               }

            }

            return !requires.length;

         }

         return false;

      },

   /**
    * checks if class path "name" is defined and declared.
    * @param {String} name the class path (e.g. "Dx.MyClass")
    * @return {Boolean} true if class is found and declared or false.
    */
      isDeclared: function(name) {

          var o = this.getDeclaration(name);

          return !!o && o.declared;

      },

   /**
    * checks if named class path has declaration registered
    * @param {String} name the class path (e.g. "Dx.MyClass")
    * @return {Boolean} true if named class path has declaration and
    *    false if none.
    */
      isRegistered: function(name) {

         var paths = this.paths;

         return paths.hasOwnProperty(name);

      },

   /**
    * retrieves the object from the given namespace path
    * @param {String} path the JS Object access path
    *    (e.g. "Dx.MyClass.prototype")
    * @param {Object=} startObject the starting object to traverse.
    *    will use Dx.GLOBAL (window object for browsers) if not an Object
    * @return {*} the property value of the namespace path
    */
      getObjectFromNamespace: function(path, startObject) {

         var D = Dx;

         return this._parsePath(

            path,

            this._callback_getObjectFromNamespace_parsePath,

            D.isObject(startObject, false) || D.isFunction(startObject) ?

               startObject :

                  D.GLOBAL

         );

      },

   /**
    * retrieves the declaration object of class "name"
    * @param {String} name the class path (e.g. "Dx.MyClass")
    * @return {Object|undefined} true if class is found and declared or false.
    */
      getDeclaration: function(name) {

         var paths = this.paths;

         return paths.hasOwnProperty(name) ? paths[name] : void(0);

      },

   /**
    * retrieves the declaration object and its
    *    Class prototype inheritance chain from a given path
    * @param {String} name the class path (e.g. "Dx.MyClass")
    * @return {Array.Object} array of declaration objects
    */
      getDeclarationPathChain: function(path) {

         var chain = [];

         var c = 0;

         var declaration = this.getDeclaration(path);

         for (; declaration = this.getDeclaration(path);) {

            chain[c++] = declaration;

            path = declaration.extended;

         }

         return chain;

      },

   /**
    * retrieves namespace declaration link object from a namespace path
    * @param {String} path the namespace path
    * @return {Object} namespace declaration link object
    */
      getNsDeclaration: function(path) {

         if (path.substring(0, 6) !== 'GLOBAL') {

            path = 'GLOBAL.' + path;

         }

         var list = this.namespaces;

         return list.hasOwnProperty(path) ? list[path] : void(0);

      },

   /**
    * retrieves callbacks from a registered class declaration
    * @param {String} path the Class path
    * @param {String} tag the tag category of the callbacks
    * @return {Object} the callback information object
    */
      getCallbacks: function(path, tag) {

         var declaration = this.getDeclaration(path);

         var callbacks = declaration && declaration.callbacks;

         return callbacks && callbacks.hasOwnProperty(tag) ?

            callbacks[tag] : void(0);

      },

   /**
    * creates a processor for class declaration object.
    *    they are called in sequence when declaring a class by prefix:
    *       "definition", "pre", ""(default), and lastly "post".
    *    ordering of calls by "tag" will be determined by "before" parameter.
    *
    * @param {String|Mixed=null} prefix processor prefix
    *    will be one of the ff:
    *    "definition", "pre", "post", or null (default)
    * @param {String} tag declaration property name prefixed with "@" that will
    *    be processed. example tag="extend" to process the declared
    *    property "@extend"
    * @param {Function} callback the processor that will be called.
    * @param {String=} before the order this processor be executed where
    *    this processor will be called before "before" processor.
    * @return {undefined}
    */
      setProcessor: function(prefix, tag, callback, before) {

         var name = prefix ? prefix + 'processors' : 'processors';

         if (name in this) {

            var processors = this[name];

            var order = this[name + 'Order'];

            var index = order.lastIndexOf(before);

            var current = order.lastIndexOf(tag);

            if (index == -1) {

               // append
               if (current == -1) {

                  order[order.length] = tag;

               } // else replace and its the same as retain

            // insert before index
            } else if (current == -1) {

               order.splice(index, 0, tag);

            // remove current and insert before index
            } else {

               // remove current then insert index
               if (index < current) {

                  order.splice(current, 1);

                  order.splice(index, 0, tag);

               // insert index then remove current
               } else {

                  order.splice(index, 0, tag);

                  order.splice(current, 1);

               }

            }

            processors[tag] = callback;

         }

      },

   /**
    * creates a non-publicize version of a class declaration.
    * @param {String} alias an alias class declaration path
    * @param {String} path the class path which will be used
    *    as base for the alias
    * @return {Object} the class declaration object found. returns undefined
    *    if not found.
    */
      setAlias: function(alias, path) {

         var declaration = this.getDeclaration(path);

         // categories can override declaration
         if (declaration) {

            this.paths[alias] = declaration;

         }

         return declaration;

      },

   /**
    * creates a callback from a given class declaration path and tag
    * @param {String} path the class path
    * @param {String} tag the tag category of the callbacks
    */
      setCallback: function(path, tag, callback) {

         var declareObject = this.getDeclaration(path);

         var callbackObject, callbacks, allCallbacks;

         // use callbacks object in declaration object
         if (declareObject) {

            callbackObject = declareObject.callbacks;

         // temporarily store callback
         } else {

            callbacks = this.temporaryCallbacks;

            if (!callbacks.hasOwnProperty(path)) {

               callbacks[path] = {};

            }

            callbackObject = callbacks[path];

         }

         if (!callbackObject.hasOwnProperty(tag)) {

            callbackObject[tag] = [];

         }

         allCallbacks = callbackObject[tag];

         allCallbacks[allCallbacks.length] = [

            callback,

            Array.prototype.slice.call(arguments, 3)

         ];

      },

   /**
    * executes all callback from a given class declaration path and
    *    tag category
    * @param {String} path the class path
    * @param {String} tag the tag category of the callbacks
    * @return {Boolean} returns true if none of the callback function
    *    returns false else it returns false.
    */
      callCallbacks: function(path, tag) {

         var callbacks = this.getCallbacks(path, tag);

         var result = !!callbacks;

         var oldProcessFlag = this.processing;

         var args, o, r, c, l;

         this.processing = true;

         // call callbacks
         if (callbacks && callbacks.length) {

            args = Array.prototype.slice.call(arguments, 2);

            for (; callbacks.length;) {

               o = callbacks.shift();

               r = o[0].apply(

                  this,

                  o[1].concat(args)

               );

               if (r === false) {

                  result = r;

               }

            }
         }

         this.processing = oldProcessFlag;

         return callbacks;

      },

   /**
    * registers the newly created class declaration object
    * @param {Object} declareObject the declaration object created from
    *    Dx.Class.createDeclareObject() method
    * @return {Boolean} returns true if object is allowed to be registered,
    *    false if doesn't.
    */
      registerDeclaration: function(declareObject) {

         var paths = this.paths;

         var name = declareObject.path;

         var allowedRegister = !paths.hasOwnProperty(name);

         if (allowedRegister) {

            paths[name] = declareObject;

            var names = this.pathNames;

            names[names.length] = name;

            // transfer callbacks
            var callbacks = this.temporaryCallbacks;

            if (callbacks.hasOwnProperty(name)) {

               declareObject.callbacks = callbacks[name];

               // remove callbacks in temporary storage
               delete callbacks[name];

            } else {

               declareObject.callbacks = {};

            }

         }

         return allowedRegister;

      },

   /**
    * creates a declaration object based on class path and definition.
    * @param {String} path the class path
    * @param {Object} definition the definition which contains
    *    the proposed class properties and processor tags.
    * @return {Object} returns the class declaration object
    */
      createDeclareObject: function(path, definition) {

         var D = Dx;

         // process name
         var pathObject = this._parsePath(

                  path,

                  this._callback_createPathObject

               );

         var properties = {};

         // finalize definition
         if (!D.isObject(definition)) {

            definition = {};

         // apply properties based on definition
         } else {

            D.each(

               definition,

               this._callback_assignNonProcessorProperty,

               properties

            );

         }

         return path && {

               ns: pathObject.ns,

               name: pathObject.name,

               declared: false,

               exposed: true,

               path: pathObject.fullName,

               definition: definition,

               properties: properties,

               isSingleton: false,

               instance: void(0),

               requires: [],

               callbacks: null

            };

      },

   /**
    * creates a namespace link object from a given path
    * @param {String} path the namespace path
    * @return {Object} returns the newly created namespace link object
    */
      createNsDeclareObject: function(path) {

         var list = this.namespaces;

         var nsPath = path ? 'GLOBAL.' + path : 'GLOBAL';

         if (!list.hasOwnProperty(nsPath)) {

            list[nsPath] = {

                  access: nsPath,

                  ns: '',

                  name: '',

                  path: path,

                  childNames: [],

                  children: {}

               };

         }

         return list[nsPath];

      },

   /**
    * Declares a class with the given path and class definitions
    * @param {String} path Class path (e.g. Application.lib)
    * @param {Object} definitions Class definition which may include
    *    class properties and process tags (e.g. "@callback" process tag)
    * @return {Boolean} true if class can be declared. false if it failed.
    */
      create: function(path, definitions) {

         var paths = this.paths;

         var declareObject = this.createDeclareObject(path, definitions);

         var canDeclare = !!declareObject &&

               this.registerDeclaration(declareObject);

         if (canDeclare) {

            var list = this.declareList;

            list[list.length] = path;

            // pre-process definition
            this._processDeclaration('definition', declareObject);

         }

         return canDeclare;

      },

   /**
    * declare undeclared class declarations that are ready to be declared.
    */
      declare: function() {

         var list = this.declareList;

         var obj, l;

         if (!this.declaring && !this.processing) {
            
            this.declaring = true;

            for (l = list.length; l--;) {

               obj = this.getDeclaration(list[l]);

               if (!obj) {

                  list.splice(l, 1);

                  continue;

               }

               if (this.canDeclare(obj.path)) {

                  this.onDeclare(obj);

                  list.splice(l, 1);

                  //-- reset
                  l = list.length;
                  
               }

            }

            delete this.declaring;

         }

      },

   /**
    * Registers instance from a namespace path
    * @param {String} path namespace or Class path (e.g. Application.lib)
    * @return {Boolean} true if instance is discovered and registered.
    *    false if not found.
    */
      discover: function(path) {

         var discovered = false;

         var D = Dx;

         var pathObject, found;

         if (this.paths.hasOwnProperty(path)) {

            // path is already registered
            return discovered;

         }

         // process name
         pathObject = this._parsePath(

            path,

            this._callback_createPathObject

         );

         found = pathObject && this.getObjectFromNamespace(pathObject.fullName);

         // discoverable objects must be native Object
         if (found instanceof Object) {

            // process with protected function
            this.onDiscover(pathObject, found);

         }

         return discovered;

      },

   /**
    * Creates or returns the object from a given path namespace
    * @param {String} path the namespace path (e.g. Application.lib)
    * @return {Object} object created or found in the defined namespace
    */
      namespace: function(path) {

         return Dx.isString(path) ?

            this._parsePath(path, this._callback_namespace_parsePath, this) :

               void(0);

      },

   /**
    * links instance to GLOBAL JSON path
    * @param {String} path namespace or Class path (e.g. Application.lib)
    * @param {Object} instance the instance to link
    */
      link: function(path, instance) {
         
         var D = Dx;
         
         var o, nsObj, childNsObj, name, ns;
         
         var parentInstance, oldInstance;
         
         var childIndexes, childNames;
         
         var cname, c, l;

         if (path && D.isString(path)) {

            // cascade ns objects
            o = this._parsePath(
               
               path,

               this._callback_namespace_declarePath,

               this

            );

            nsObj = o[0];

            name = o[1];

            ns = nsObj.path;

            path = ns ?
               
               ns + '.' + name
               
               :
               
               name;

            parentInstance = ns ?
               
               this.getObjectFromNamespace(ns) : D.GLOBAL;

            oldInstance = this.getObjectFromNamespace(path);

            childNsObj = this.getNsDeclaration(path);

            // relink children
            if (childNsObj) {

               childNames = childNsObj.childNames;

               if (Dx.isObject(oldInstance, false)) {

                  for (c = -1, l = childNames.length; l--;) {

                     cname = childNames[++c];

                     if (cname in oldInstance) {

                        instance[cname] = oldInstance[cname];

                     }

                  }
                  
               }

            }

            // link instance
            childIndexes = nsObj.children;

            if (!childIndexes.hasOwnProperty(name)) {

               childNames = nsObj.childNames;

               childNames[childNames.length] = name;

               childIndexes[name] = true;

            }

            parentInstance[name] = instance;

         }

      }

   }));


////////////////////////////////////////////////////////////////////////
// Shortcuts
////////////////////////////////////////////////////////////////////////

/**
 * shortcut for Dx.Class.namespace
 * @param {String} path the namespace path (e.g. Application.lib)
 * @return {Object} object created or found in the defined namespace
 */
Dx.ns = function(path) {

   return Dx.Class.namespace(path);

};

/**
 * Returns a Class constructor from a given declared Class "path"
 * @param {String} path the declaration path
 * @return {Function} the Class constructor
 */
Dx.getClass = function(path) {

   var d = Dx.Class.getDeclaration(path);

   var instance = void(0);

   if (d && d.declared) {

      instance = d.instance;

      if (d.isSingleton) {

         instance = instance.constructor;

      }

   }

   return instance;

};

/**
 * Returns an instance from a declared Class "path"
 * @param {String} path the declaration path
 * @return {Object|Function} the instance from a given Class "path". It may be
 *    a singleton class or a Function constructor of a class.
 */
Dx.getInstance = function(path) {
   
   var d = Dx.Class.getDeclaration(path);
   
   return d && d.declared ?
      
      d.instance : void(0);
   
};

/**
 * Checks if instance arguments is an instance of Class Function
 * @param {String|Function} Class if String is passed
 *    it will look into the declared Classes from path. And find its Function
 *    constructor.
 * @param {*} instance the instance to check if its an instance to Class
 * @return {Boolean} returns true if instance is an instance of Class, and
 *    false if not.
 */
Dx.instanceOf = function(Class, instance) {

   var D = Dx;

   if (D.isString(Class)) {

      Class = D.getClass(Class);

   }

   if (D.isFunction(Class)) {

      return instance instanceof Class;

   }

   return false;

};

/**
 * Checks if "subject" is a subclass of "Class". They can be in a form of
 *    string Class "path" or a constructor Function.
 * @param {String|Function} Class if String is passed
 *    it will look into the declared Classes from path. And find its Function
 *    constructor.
 * @param {String|Function} Class if String is passed
 *    it will look into the declared Classes from path. And find its Function
 *    constructor.
 * @return {Boolean} returns true if "Class" is a subclass of "subject" or
 *    false if not.
 */
Dx.subclassOf = function(Class, subject) {

   var D = Dx;

   var Proto;

   if (D.isString(Class)) {

      Class = D.getClass(Class);

   }
   
   if (D.isString(subject)) {
      
      subject = D.getClass(subject);
      
   }

   if (D.isFunction(Class) && D.isFunction(subject)) {

      Proto = subject.prototype;

      return Proto instanceof Class || Proto === Class.prototype;

   }

   return false;

};

/**
 * Instantiates a Class and calling constructor with Array of arguments
 * @param {String|Function} path if String is passed
 *    it will look into the declared Classes from path.
 *    If Function is provided, it will directly instantiate the Class
 * @param {Array=} constructorArguments the arguments to pass to the
 *    instance's constructor.
 * @return {Object} the instance of the Class if successfully instantiated
 *    undefined if not.
 */
Dx.instantiate = function(path, constructorArguments) {

   var D = Dx;

   var Class = path instanceof Function ?

         path : D.getClass(path);

   var instance = void(0);

   if (Class) {

      instance = D.createObject(Class);

      Class.apply(instance, constructorArguments || []);

   }

   return instance;

};

/**
 * shortcut for Dx.Class.setProcessor
 * @param {String|Mixed=null} prefix processor prefix
 *    will be one of the ff:
 *    "definition", "pre", "post", or null (default)
 * @param {String} tag declaration property name prefixed with "@" that will
 *    be processed. example tag="extend" to process declared property "@extend"
 * @param {Function} callback the processor that will be called.
 * @param {String=} before the order this processor be executed where
 *    this processor will be called before "before" processor.
 * @return {*} anything what Dx.Class.setProcessor() returns
 */
Dx.setClassProcessor = function(prefix, tag, callback, before) {

   return Dx.Class.setProcessor(prefix, tag, callback, before);

};

/**
 * Declares a class with the given path and class definitions
 * @param {String} path Class path (e.g. Application.lib)
 * @param {Object} definitions Class definition which may include
 *    class properties and process tags (e.g. "@callback" process tag)
 * @return {Boolean} true if class can be declared. false if it failed.
 */
Dx.declare = function(path, definitions) {

   var D = Dx;

   var DClass = D.Class;

   var canDeclare = D.isObject(definitions) && path && D.isString(path) ?

         DClass.create(path, definitions) : false;

   if (canDeclare) {

      DClass.declare();

   }

   return canDeclare;

};

/**
 * Declares a non-publicly exposed class
 *    with the given path and class definitions.
 *    a shortcute for Dx.declare('Namespace.MyClass', {'@public': false});
 * @this Dx class
 * @param {String} path Class path (e.g. Application.lib)
 * @param {Object} definitions Class definition which may include
 *    class properties and process tags (e.g. "@callback" process tag)
 * @return {Boolean} true if class can be declared. false if it failed.
 */
Dx.categorize = function(path, definitions) {

   if (Dx.isObject(definitions)) {

      definitions['@public'] = false;

   }

   return this.declare(path, definitions);

};

/**
 * Registers instance from a namespace path
 * @param {String} path namespace or Class path (e.g. Application.lib)
 * @return {Boolean} true if instance is discovered and registered.
 *    false if not found.
 */
Dx.discover = function(path) {

   var DClass = Dx.Class;

   var discovered = DClass.discover(path);

   if (discovered) {

      DClass.declare();

   }

   return discovered;

};

// discover Dx.Class JSON path
Dx.discover('Dx.Class');
